﻿using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;

namespace Mars.MeshUI
{
    public class MeshText : CustomUIGraphic
    {
        private bool textDirty = false;
        public int fontSize = 0;
        public int maxCount = 8;
        private int nowCount;
        public float pixelsPerUnit = 100;
        private string m_Text = string.Empty;
        [SerializeField] private FontData m_FontData = FontData.defaultFontData;
        private string m_FontName = string.Empty;
        public Color color = default;
        public Font meshFont;
        private TextGenerator m_TextCache;
        
        private TextGenerationSettings settings;
        private bool changeTextAnchorWhenWideWidth = false;
        private int wMax = 106;
        private TextAnchor longWidthAnchor = TextAnchor.LowerLeft;
        private TextAnchor normalWidthAnchor = TextAnchor.LowerCenter;
        
        public TextGenerator cachedTextGenerator
        {
            get
            {
                return m_TextCache ?? (m_TextCache =
                    (m_Text.Length != 0 ? new TextGenerator(m_Text.Length) : new TextGenerator()));
            }
        }

        public string text
        {
            get => m_Text;

            set
            {
                if (m_Text == value)
                {
                    return;
                }

                m_Text = value;
                maxCount = m_Text.Length * 4;
                textDirty = true;
            }
        }

        public void RefreshFont(Font font)
        {
            if (m_FontData != null && m_FontData.font != null)
            {
                m_FontData.font = font;
                settings.font = m_FontData.font;
                if (m_FontData.font != null && m_FontData.font.dynamic)
                {
                    settings.fontSize = fontSize;
                    settings.resizeTextMinSize = m_FontData.minSize;
                    settings.resizeTextMaxSize = m_FontData.maxSize;
                }

                RefreshMaterialFontTexture();
            }
        }

        public override bool Init(MeshCanvas _canvas)
        {
            this.canvas = _canvas;
            AutoSetFont();
            settings = GetGenerationSettings(size);
            Font.textureRebuilt += FontTextureChanged;
            normalWidthAnchor = m_FontData.alignment;

            if (gameObject != null)
            {
                SetVisable(true);
            }

            //for test
            string hpText = "88888/99999";
            text = hpText;
            return true;
        }

        public void FontTextureChanged(Font font)
        {
            if (font != m_FontData.font)
            {
                return;
            }

            cachedTextGenerator.Invalidate();

            textDirty = true;
        }

        void OnDestroy()
        {
            Font.textureRebuilt -= FontTextureChanged;
        }

        private void SetText()
        {
            if (canvas == null)
            {
                return;
            }

            if (isVisible == false)
            {
                return;
            }

            if (m_FontData.font == null)
            {
                return;
            }

            if (string.IsNullOrEmpty(text))
            {
                return;
            }

            if (changeTextAnchorWhenWideWidth)
            {
                float w = cachedTextGenerator.GetPreferredWidth(text, settings);
                settings.textAnchor = w > wMax ? longWidthAnchor : normalWidthAnchor;
            }

            cachedTextGenerator.PopulateWithErrors(text, settings, gameObject);

            IList<UIVertex> verts = cachedTextGenerator.verts;
            float unitsPerPixel = 1 / pixelsPerUnit;

            int vertCount = verts.Count - 4;

            if (vertices == null || vertices.Length == 0)
            {
                vertices = new VertexData[maxCount];
            }
            else if (vertices.Length < maxCount)
            {
                vertices = new VertexData[maxCount];
            }

            if (vertCount > vertices.Length)
            {
                vertCount = vertices.Length;
            }
            else if (vertCount < 0)
            {
                vertCount = 0;
            }


            for (int i = 0; i < vertCount; ++i)
            {
                vertices[i].position =
                    canvas.transform.InverseTransformPoint(transform.TransformPoint(verts[i].position * unitsPerPixel));
                vertices[i].uv.z = verts[i].uv0.x;
                vertices[i].uv.w = verts[i].uv0.y;
                vertices[i].color = verts[i].color;
            }

            if (nowCount > vertCount)
            {
                for (int i = vertCount; i < nowCount; i++)
                {
                    vertices[i].position = Vector3.zero;
                }
            }

            nowCount = vertCount;

            SetCanvasFlagDirty(MeshCanvasDirtyFlag.kAll);
            SetCanvasVertexDirty();
        }

        public override void SetSize(Vector2 size)
        {
            base.SetSize(size);

            settings.generationExtents = size;
            textDirty = true;
        }

        public override bool Rebuild()
        {
            if (isVisible == false)
            {
                return false;
            }

            if (textDirty)
            {
                SetText();
                textDirty = false;
            }
            else if (positionDrity)
            {
                for (int i = 0; i < nowCount; i++)
                {
                    vertices[i].position += deltaPostion;
                }

                SetCanvasFlagDirty(MeshCanvasDirtyFlag.kPosition);
            }

            positionDrity = false;
            sizeDrity = false;
            deltaSize = Vector2.zero;
            deltaPostion = Vector3.zero;

            return true;
        }

        public override void SetVisable(bool enable)
        {
            if (canvas == null)
            {
                return;
            }

            isVisible = enable;
            SetCanvasVertexDirty();
        }

        public void SetCanvasVertexDirty()
        {
            canvas.SetVertexDataById(MeshCanvasIndex, vertices, IndicType);
            canvas.SetVertexLenghtDirtyById(MeshCanvasIndex, nowCount);
            canvas.SetVisibleDirtyById(MeshCanvasIndex, isVisible);
        }

        public TextGenerationSettings GetGenerationSettings(Vector2 extents)
        {
            var settings = new TextGenerationSettings();

            settings.generationExtents = extents;
            if (m_FontData.font != null && m_FontData.font.dynamic)
            {
                settings.fontSize = fontSize;
                settings.resizeTextMinSize = m_FontData.minSize;
                settings.resizeTextMaxSize = m_FontData.maxSize;
            }

            // // Other settings
            settings.textAnchor = m_FontData.alignment;
            settings.alignByGeometry = m_FontData.alignByGeometry;
            settings.scaleFactor = pixelsPerUnit;
            settings.color = color;
            settings.font = m_FontData.font;
            settings.pivot = pivot;
            settings.richText = m_FontData.richText;
            settings.lineSpacing = m_FontData.lineSpacing;
            settings.fontStyle = m_FontData.fontStyle;
            settings.resizeTextForBestFit = m_FontData.bestFit;
            settings.updateBounds = false;
            settings.horizontalOverflow = m_FontData.horizontalOverflow;
            settings.verticalOverflow = m_FontData.verticalOverflow;

            return settings;
        }

        public void SetSetting(TextGenerationSettings set)
        {
            size = set.generationExtents;
            pivot = set.pivot;
            color = set.color;
            fontSize = set.fontSize;
            pixelsPerUnit = set.scaleFactor;
            m_FontData.font = set.font;
            m_FontData.fontSize = set.fontSize;
            m_FontData.minSize = set.resizeTextMinSize;
            m_FontData.maxSize = set.resizeTextMaxSize;
            m_FontData.alignment = set.textAnchor;
            m_FontData.richText = set.richText;
            m_FontData.lineSpacing = set.lineSpacing;
            m_FontData.fontStyle = set.fontStyle;
            m_FontData.bestFit = set.resizeTextForBestFit;
            m_FontData.horizontalOverflow = set.horizontalOverflow;
            m_FontData.verticalOverflow = set.verticalOverflow;
            if (m_FontData.font != null)
            {
                m_FontName = m_FontData.font.name;
            }
#if UNITY_EDITOR
            if (null != set.font)
            {
                m_FontName = set.font.name;
            }

            m_FontData.font = null;
#endif
        }

        public FontData Getm_FontData()
        {
            return m_FontData;
        }

        private void AutoSetFont()
        {
#if UNITY_EDITOR
            if (!Application.isPlaying)
            {
                return;
            }
#endif
            if ((null != canvas && null != canvas.render && null != canvas.render.sharedMaterial &&
                 null != m_FontData.font && null != m_FontData.font.material))
            {
                RefreshMaterialFontTexture();
            }

            string fontname = (null == m_FontData.font) ? m_FontName : m_FontData.font.name;

            Font curFont = meshFont; //据字体名字来获取当前语言对应的默认Text字体
            if (null != curFont)
            {
                m_FontData.font = curFont;
                m_FontName = curFont.name;
            }


            if ((null != canvas && null != canvas.render && null != canvas.render.sharedMaterial &&
                 null != m_FontData.font && null != m_FontData.font.material))
            {
                RefreshMaterialFontTexture();
            }
        }

        private void RefreshMaterialFontTexture()
        {
            if (null != canvas && null != canvas.render && null != canvas.render.sharedMaterial &&
                null != m_FontData.font && null != m_FontData.font.material)
            {
                if (canvas.useMaterialCopy)
                {
                    canvas.render.material.SetTexture("_FontTex", m_FontData.font.material.GetTexture("_MainTex"));
                }
                else
                {
                    canvas.render.sharedMaterial.SetTexture("_FontTex",
                        m_FontData.font.material.GetTexture("_MainTex"));
                }
            }
        }


        public void SetTextAnchorDynamic(bool open, TextAnchor mlongWidthAnchor)
        {
            changeTextAnchorWhenWideWidth = open;
            longWidthAnchor = mlongWidthAnchor;
            textDirty = true;
            if (!changeTextAnchorWhenWideWidth && null != m_FontData)
            {
                settings.textAnchor = m_FontData.alignment;
            }
        }
    }
}